﻿<script setup lang="ts" name="EpTree">
import { cloneDeep } from 'lodash-es'
import { transformI18n } from '@/plugins/i18n'
import type Node from 'element-plus/es/components/tree/src/model/node'
import type { DragEvents } from 'element-plus/es/components/tree/src/model/useDragNode'
import type { TreeNode } from 'element-plus/es/components/tree-v2/src/types'
import { useRouteMenuStore } from '@/store/routeMenu/routeMenuStore'
import { storeToRefs } from 'pinia'
import { useSystemConfigStore } from '@/store/storage/systemConfigStore'
const systemConfigStore = useSystemConfigStore()
const { systemConfig } = storeToRefs(systemConfigStore)
// 获取路由菜单数据
const routeMenuStore = useRouteMenuStore()
const { routeMenuList } = storeToRefs(routeMenuStore)

const expandNodes = ref([])
// 树结构数据添加线条结构
const treeData = (data, isLast, hideLine, level, parentId) => {
  data.forEach((item, index) => {
    item.label = transformI18n('menus.' + item.meta.title, item.meta.i18n)
    item.id = item.meta.id
    item.value = item.meta.id
    item.meta.level = level + 1
    item.parentId = parentId
    if (index === 0) {
      item.isFirst = true
    } else {
      item.isFirst = false
    }
    if (index === data.length - 1) {
      item.isLast = true
    } else {
      item.isLast = false
    }
    item.hideLine = cloneDeep(hideLine)
    if (isLast) {
      item.hideLine.push(item.level - 1)
    }
    if (item.children && item.children.length > 0) {
      expandNodes.value.push(item.id)
      treeData(item.children, item.isLast, item.hideLine, level + 1, item.id)
    }
  })
}

const treeDataBack = (data) => {
  treeData(data, false, [], 0, '')
  return data
}
const menuData = ref(treeDataBack(cloneDeep(routeMenuList.value)))
const menuList: any = computed({
  set: (val) => {
    menuData.value = treeDataBack(val)
    console.log(menuData.value)
  },
  get: () => menuData.value
})
const nodeExpandChange = (v) => {
  expandNodes.value.push(v.id)
}

const nodeCollapseChange = (v) => {
  const index = expandNodes.value.findIndex((item) => item === v.id)
  if (index >= 0) {
    expandNodes.value.splice(index, 1)
  }
}

interface Tree {
  id: number,
  label: string,
  value: number,
  children?: Tree[],
  isLast?: boolean,
  isFirst?: boolean,
  hideLine?: [],
  meta: {
    level: number,
  }
}
const defaultProps = {
  children: 'children',
  label: 'label'
}
const handleNodeClick = (data: Tree) => {
  console.log(data)
}
// 树形控件选择事件
const handleCheckChange = (
  data: Tree,
  checked: boolean,
  indeterminate: boolean
) => {
  console.log(data, checked, indeterminate)
}
// 过滤筛选事件
const filterText = ref('')
const filterNode = (value: string, data: Tree) => {
  if (!value) return true
  return data.label.includes(value)
}
const treeRef = ref()
watch(
  () => filterText.value,
  (val) => {
    treeRef.value?.filter(val)
  })
const editMenuData = (data, item, newChild) => {
  data.forEach((current) => {
    if (current.id === item.meta.id) {
      if (!current.children) {
        current.children = []
      }
      current.children.push(newChild)
    } else {
      if (current.children && current.children.length > 0) {
        editMenuData(current.children, item, newChild)
      }
    }
  })
}
let id = 1000
const append = (data: Tree) => {
  const newChild = { id: 0, value: 0, label: '', children: [], meta: { id: id++, title: '测试节点', level: data.meta.level + 1 } }
  editMenuData(menuList.value, data, newChild)
  menuList.value = treeDataBack(menuList.value)
}

const remove = (node: Node, data: Tree) => {
  console.log(node, 'node')
  console.log(data, '数据')
  const parent = node.parent
  const children: Tree[] = parent.data.children || parent.data
  const index = children.findIndex((d) => d.id === data.id)
  children.splice(index, 1)
  menuList.value = [...menuList.value]
}

const handleDragStart = (node: Node, ev: DragEvents) => {
  console.log('拖拽开始：', node, ev)
}
const handleDragEnter = (
  draggingNode: Node,
  dropNode: Node,
  ev: DragEvents
) => {
  console.log('拖拽进入：', dropNode.label, ev)
}
const handleDragLeave = (
  draggingNode: Node,
  dropNode: Node,
  ev: DragEvents
) => {
  console.log('拖拽离开：', dropNode.label, ev)
}
const handleDragOver = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
  console.log('拖拽到:', dropNode.label, ev)
}
const handleDragEnd = (
  draggingNode: Node,
  dropNode: Node,
  dropType: any,
  ev: DragEvents
) => {
  console.log('拖拽结束:', dropNode && dropNode.label, dropType, ev)
}
const handleDrop = (
  draggingNode: Node,
  dropNode: Node,
  dropType: any,
  ev: DragEvents
) => {
  console.log('拖拽落下:', dropNode.label, dropType, ev)
}
// 判断拖拽时，目标节点能否成为拖动的目标位置，如果返回false，拖动节点不能被放到目标节点
const allowDrop = (draggingNode: Node, dropNode: Node, type: any) => {
  if (dropNode.data.label === '数据') {
    return type !== 'inner'
  } else {
    return true
  }
}
// 判断当前节点能否被拖拽
const allowDrag = (draggingNode: Node) => {
  return !draggingNode.data.label.includes('表单')
}

const value = ref()

const query = ref('')
const treeV2Ref = ref()

const onQueryChanged = (query: string) => {
  treeV2Ref.value?.filter(query)
}
const filterMethod = (query: string, node: TreeNode) => {
  return node.label?.includes(query)
}
</script>
<template>
  <div class="ep-tree-page">
    <el-row :gutter="systemConfig.space">
      <el-col :xs="24" :sm="8">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>树形控件</span>
            </div>
          </template>
          <el-alert title="当前控件可筛选、拖拽、选择、折叠、展开、添加、删除，扩展结构连接线" type="success" :closable="false" show-icon />
          <el-input v-model="filterText" placeholder="筛选菜单" />
          <el-tree
            ref="treeRef"
            class="tree-level"
            :data="menuData"
            :props="defaultProps"
            @node-click="handleNodeClick"
            show-checkbox
            @check-change="handleCheckChange"
            :filter-node-method="filterNode"
            :allow-drop="allowDrop"
            :allow-drag="allowDrag"
            draggable
            auto-expand-parent
            :default-expanded-keys="expandNodes"
            :expand-on-click-node="false"
            :check-on-click-node="false"
            node-key="id"
            @node-drag-start="handleDragStart"
            @node-drag-enter="handleDragEnter"
            @node-drag-leave="handleDragLeave"
            @node-drag-over="handleDragOver"
            @node-drag-end="handleDragEnd"
            @node-drop="handleDrop"
            @node-expand="nodeExpandChange"
            @node-collapse="nodeCollapseChange">
            <template #default="{ node, data }">
              <span class="item-tree-node">
                <span>{{ node.label }}</span>
                <template v-for="item in data.meta.level">
                  <span v-if="!data.hideLine.includes(item)" :key="item.value" :class="['item-tree-node-line-vertical', data.isLast && item == data.meta.level ? 'is-last' : '', data.isFirst && data.meta.level === 1 ? 'is-first' : '']" :style="{ left: 18 * (item - 1) + 12 + 'px' }"></span>
                </template>
                <span v-if="data.children.length > 0 && expandNodes.includes(data.id)" class="item-tree-node-line-vertical halfway" :style="{ left: 18 * (data.meta.level - 1) + 17 + 12 + 1 + 'px' }"></span>
                <span class="item-tree-node-line-horizontal" :style="{ left: 18 * (data.meta.level - 1) + 12 + 1 + 'px' }"></span>
              </span>
              <el-link @click="append(data)">添加</el-link>
              <el-link @click="remove(node, data)">删除</el-link>
            </template>
          </el-tree>
        </el-card>
      </el-col>
      <el-col :xs="24" :sm="8">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>树选择</span>
            </div>
          </template>
          <el-alert title="当前控件可筛选、选择、折叠、展开" type="success" :closable="false" show-icon />
          <el-tree-select style="width: 100%;" v-model="value" :data="menuList" multiple show-checkbox check-strictly filterable placeholder="请选择菜单节点" />
        </el-card>
      </el-col>
      <el-col :xs="24" :sm="8">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>虚拟化树形控件</span>
            </div>
          </template>
          <el-alert title="当前控件可筛选，选择、折叠、展开；为大数据量专用，需用插件自身滚动条" type="success" :closable="false" show-icon />
          <el-input v-model="query" placeholder="请输入关键词" @input="onQueryChanged" />
          <el-tree-v2 ref="treeV2Ref" :data="menuList" :filter-method="filterMethod" show-checkbox :height="600" />
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<style scoped lang="scss">
.ep-tree-page {
  padding: var(--el-space);

  .el-row {
    flex: 1;

    .el-col {
      display: flex;

      .el-card {
        flex: 1;
      }
    }
  }
}

.el-alert {
  margin-bottom: var(--el-space);
}

.el-input {
  margin-bottom: var(--el-space);
}

.el-tree {
  background: transparent;

  &.tree-level .item-tree-node {
    padding-left: 0;
  }

  :deep(.el-tree-node__content) {
    height: 32px;

    .el-link {
      margin: 0 6px;
    }
  }
}
</style>
